package com.onlyxiahui.extend.query.hibernate.handler.result;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.DefaultConversionService;

import com.onlyxiahui.extend.query.hibernate.handler.result.config.AllCustomDateEditor;
import com.onlyxiahui.extend.query.hibernate.handler.result.config.DateDeserializerConverter;
import com.onlyxiahui.extend.query.hibernate.handler.result.config.DateSerializerConverter;

/**
 * 
 * Date 2018-12-28 16:44:37<br>
 * Description
 * 
 * @author XiaHui<br>
 * @since 1.0.0
 */
public class BeanResolver {

	static final BeanResolver BEAN_RESOLVER = new BeanResolver();
	protected final DefaultConversionService conversionService = new DefaultConversionService();
	protected final Map<Object, List<PropertyDescriptor>> writeMethodPropertyDescriptorListMap = new HashMap<>();

	public BeanResolver() {
		Converter<String, Date> dateDeserializerConverter = new DateDeserializerConverter();
		Converter<Date, String> dateSerializerConverter = new DateSerializerConverter();
		conversionService.addConverter(String.class, Date.class, dateDeserializerConverter);
		conversionService.addConverter(Date.class, String.class, dateSerializerConverter);
		
		conversionService.addConverter(Date.class, String.class, dateSerializerConverter);
		conversionService.addConverter(Date.class, String.class, dateSerializerConverter);
	}

	public <T> T resolver(Class<T> classType, Map<String, Object> dataMap) {
		int size = dataMap.size();
		Map<String, Object> map = new HashMap<>(size);
		Set<String> keySet = dataMap.keySet();

		for (String key : keySet) {
			String name = key.replace("_", "").toLowerCase();
			map.put(name, dataMap.get(key));
		}

		T object = null;
		try {
			object = classType.newInstance();

			BeanWrapper beanWrapper = new BeanWrapperImpl(object);
			beanWrapper.registerCustomEditor(Date.class, null, new AllCustomDateEditor());

			List<PropertyDescriptor> propertyDescriptorList = this.getWriteMethodPropertyDescriptorList(classType);
			for (PropertyDescriptor pd : propertyDescriptorList) {
				String propertyName = pd.getName();
				String key = propertyName.replace("_", "").toLowerCase();
				Object value = map.get(key);
				if (null != value) {
					if (conversionService.canConvert(value.getClass(), pd.getPropertyType())) {
						value = conversionService.convert(value, pd.getPropertyType());
					}
					beanWrapper.setPropertyValue(propertyName, value);
				}
			}
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		}
		return object;
	}

	public <T> T resolver(Class<T> classType, Object[] values, String[] names) {

		int namesLength = names.length;
		int valuesLength = values.length;
		int length = 0;

		if (namesLength == valuesLength) {
			length = namesLength;
		} else if (namesLength > valuesLength) {
			length = valuesLength;
		} else {
			length = namesLength;
		}

		Map<String, Object> map = new HashMap<>(length);
		for (int i = 0; i < length; i++) {
			String name = names[i];
			Object value = values[i];

			if (null != name && !"".equals(name)) {
				String key = name.replace("_", "").toLowerCase();
				map.put(key, value);
			}
		}

		T object = null;
		try {
			// Class.forName(classType.getName()).newInstance();
			object = classType.newInstance();
			List<PropertyDescriptor> propertyDescriptorList = this.getWriteMethodPropertyDescriptorList(classType);
			for (PropertyDescriptor pd : propertyDescriptorList) {
				String propertyName = pd.getName();
				Method writeMethod = pd.getWriteMethod();
				String key = propertyName.replace("_", "").toLowerCase();
				Object value = map.get(key);
				if (null != value) {
					if (conversionService.canConvert(value.getClass(), pd.getPropertyType())) {
						value = conversionService.convert(value, pd.getPropertyType());
						writeMethod.invoke(object, value);
					}
				}
			}
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		}
		return object;
	}

	/**
	 * 获取类中有set方法是属性
	 * 
	 * @param classType
	 * @return
	 */
	public List<PropertyDescriptor> getWriteMethodPropertyDescriptorList(Class<?> classType) {
		List<PropertyDescriptor> propertyDescriptorList = writeMethodPropertyDescriptorListMap.get(classType);
		try {
			if (null == propertyDescriptorList) {
				propertyDescriptorList = new ArrayList<>();
				BeanInfo bi = Introspector.getBeanInfo(classType, Object.class);
				PropertyDescriptor[] pds = bi.getPropertyDescriptors();
				for (PropertyDescriptor pd : pds) {
					if (null != pd.getWriteMethod()) {
						propertyDescriptorList.add(pd);
					}
				}
				writeMethodPropertyDescriptorListMap.put(classType, propertyDescriptorList);
			}
		} catch (IntrospectionException e) {
			e.printStackTrace();
		}
		return propertyDescriptorList;
	}

	

	public static <T> T beanResolver(Class<T> classType, Object[] values, String[] names) {
		return BEAN_RESOLVER.resolver(classType, values, names);
	}

	public static <T> T beanResolver(Class<T> classType, Map<String, Object> dataMap) {
		return BEAN_RESOLVER.resolver(classType, dataMap);
	}
}
